/**
 * <pre>
 * @(#)TitleView.java 1.00 2009-8-26
 * 
 * Copyright (c) 1998, 2009 Regular Individual. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Contributor(s):
 *     Haixu Huang
 * </pre>
 **/
package cn.sh.huang.chart.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;

import cn.sh.huang.chart.ext.ChartUtilities;
import cn.sh.huang.chart.ext.enumtype.Direction;
import cn.sh.huang.chart.ext.enumtype.Extension;
import cn.sh.huang.chart.ext.enumtype.Overflow;
import cn.sh.huang.chart.ext.enumtype.Position;
import cn.sh.huang.chart.ext.enumtype.Side;
import cn.sh.huang.chart.config.TitleConfig;

/**
 * <pre>
 * TitleView ...
 * 
 * @version 1.0
 * </pre>
 */
final public class TitleView extends BufferView implements SideView
{
    private final TitleConfig config = new TitleConfig(this);

    public TitleView(String title)
    {
        setText(title);
        setPosition(Position.CENTER_TOP);
    }

    public TitleConfig getConfig()
    {
        return config;
    }

    public Direction getDirection()
    {
        return config.getDirection();
    }

    public Extension getExtension()
    {
        return config.getExtension();
    }

    public Position getPosition()
    {
        return config.getPosition();
    }

    private Dimension getTitleViewSize(boolean isPreferred)
    {
        FontMetrics fm = DEFAULT_CANVAS.getFontMetrics(config.getFont());
        Direction d = config.getDirection(); // Rendering of text is only concerned with direction and extension
        Extension e = config.getExtension();
        String title = config.getTitle();
        int stringWidth = 0, stringHeight = 0;
        if (title != null) {
            title = title.trim();
            if (title.length() != 0) {
                if (e.equals(Extension.TANGENT)) {
                    stringWidth = isPreferred ? fm.stringWidth(title) : MINIMUM_VIEW_WIDTH;
                    stringHeight = fm.getHeight();
                } else { // NORMAL
                    for (int i = 0; i < title.length(); i++) {
                        stringWidth = Math.max(stringWidth, fm.charWidth(title.charAt(i)));
                    }
                    stringHeight = isPreferred ? fm.getHeight() * title.length() : MINIMUM_VIEW_WIDTH;
                }
            }
        }
        if (d.westOrEast()) {
            return new Dimension(stringHeight, stringWidth);
        } else {
            return new Dimension(stringWidth, stringHeight);
        }
    }

    public Dimension getPreferredSize()
    {
        return getTitleViewSize(true);
    }

    public Dimension getMinimumSize()
    {
        return getTitleViewSize(false);
    }

    private Overflow setOverflow(Position p, Side left, Side right)
    {
        if (p.onTheSide(left)) {
            return Overflow.TAIL;
        } else if (p.onTheSide(right)) {
            return Overflow.HEAD;
        } else {
            return Overflow.BOTH;
        }
    }

    protected void renderBuffer(Graphics2D g2d)
    {
        String title = config.getTitle();
        if (title == null) {
            return;
        }
        title = title.trim();
        if (title.length() == 0) {
            return;
        }
        g2d.setColor(config.getColor());
        g2d.setFont(config.getFont());
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, config.getTextRenderingHint());
        Direction d = config.getDirection(); // Rendering of text is only concerned with direction and extension
        Extension e = config.getExtension();
        Position p = config.getPosition();
        Overflow o = config.getOverflow();

        if (o.equals(Overflow.AUTO)) {
            if (e.equals(Extension.TANGENT)) {
                if (d.equals(Direction.NORTH)) {
                    o = setOverflow(p, Side.LEFT, Side.RIGHT);
                } else if (d.equals(Direction.WEST)) {
                    o = setOverflow(p, Side.BOTTOM, Side.TOP);
                } else if (d.equals(Direction.SOUTH)) {
                    o = setOverflow(p, Side.RIGHT, Side.LEFT);
                } else { // EAST
                    o = setOverflow(p, Side.TOP, Side.BOTTOM);
                }
            } else { // NORMAL
                if (d.equals(Direction.NORTH)) {
                    o = setOverflow(p, Side.TOP, Side.BOTTOM);
                } else if (d.equals(Direction.WEST)) {
                    o = setOverflow(p, Side.LEFT, Side.RIGHT);
                } else if (d.equals(Direction.SOUTH)) {
                    o = setOverflow(p, Side.BOTTOM, Side.TOP);
                } else { // EAST
                    o = setOverflow(p, Side.RIGHT, Side.LEFT);
                }
            }
        }
        Dimension viewSize = getViewSize();
        int rectWidth = d.northOrSouth() ? viewSize.width : viewSize.height;
        int rectHeight = d.northOrSouth() ? viewSize.height : viewSize.width; // Rectangle of rendering text

        FontMetrics fm = g2d.getFontMetrics();
        int stringWidth = e.equals(Extension.TANGENT) ? fm.stringWidth(title) : fm.charWidth(title.charAt(0));
        int stringHeight = e.equals(Extension.TANGENT) ? fm.getHeight() : fm.getHeight() * title.length(); // Real length of text
        String label = null;
        if (o.equals(Overflow.ZOOM)) {
            label = title;
            o = Overflow.BOTH;
            double zoom = e.equals(Extension.TANGENT) ? // zoom by extension
                ((double) rectWidth) / stringWidth : // TANGENT
                ((double) rectHeight) / stringHeight; // NORMAL
            if (zoom < 1 - 1E-4) {
                Font oldFont = config.getFont();
                int fontSize = (int) (zoom * oldFont.getSize());
                Font font = new Font(oldFont.getName(), oldFont.getStyle(), fontSize);
                g2d.setFont(font);
                fm = g2d.getFontMetrics(); // Reset fm
            }
        } else { // To check if text is overflow
            int extWidth = e.equals(Extension.TANGENT) ? rectWidth : rectHeight; // Size on extension
            label = ChartUtilities.getPreferredSubLabel(fm, title, extWidth, o, e);
        }
        stringWidth = e.equals(Extension.TANGENT) ? fm.stringWidth(label) : fm.charWidth(label.charAt(0));
        stringHeight = e.equals(Extension.TANGENT) ? fm.getHeight() : fm.getHeight() * label.length(); // Re-calculate the real size of text

        AffineTransform oldTransform = g2d.getTransform();
        if (d.equals(Direction.WEST)) {
            g2d.transform(AffineTransform.getTranslateInstance(0, viewSize.height)); // Move to left-bottom corner
            g2d.transform(AffineTransform.getRotateInstance(Math.PI * -.5)); // Rotate - PI / 2 degree
        } else if (d.equals(Direction.EAST)) {
            g2d.transform(AffineTransform.getTranslateInstance(viewSize.width, 0)); // Move to right-top corner
            g2d.transform(AffineTransform.getRotateInstance(Math.PI * .5)); // Rotate PI / 2 degree
        } else if (d.equals(Direction.SOUTH)) {
            g2d.transform(AffineTransform.getTranslateInstance(viewSize.width, viewSize.height)); // Move to right-bottom corner
            g2d.transform(AffineTransform.getRotateInstance(Math.PI)); // Rotate PI degree
        }
        if (e.equals(Extension.TANGENT)) {
            int x =
                o.equals(Overflow.TAIL) ? 0 : (o.equals(Overflow.BOTH) ? (rectWidth - stringWidth) / 2 : rectWidth
                    - stringWidth);
            int y = (rectHeight - stringHeight) / 2 + fm.getAscent();
            g2d.drawString(label, x, y);
        } else { // NORMAL
            int l = label.length();
            int y =
                fm.getAscent()
                    + (o.equals(Overflow.TAIL) ? 0 : (o.equals(Overflow.BOTH) ? (rectHeight - stringHeight) / 2
                        : rectHeight - stringHeight));
            int charHeight = fm.getHeight();
            char[] chars = label.toCharArray();
            for (int k = 0; k < l; k++) {
                int x = (rectWidth - fm.charWidth(chars[k])) / 2;
                g2d.drawChars(chars, k, 1, x, y);
                y += charHeight;
            }
        }
        g2d.setTransform(oldTransform);
    }

    public void setColor(Color color)
    {
        config.setColor(color);
    }

    public void setDirection(Direction d)
    {
        config.setDirection(d);
    }

    public void setExtension(Extension e)
    {
        config.setExtension(e);
    }

    public void setFont(Font font)
    {
        config.setFont(font);
    }

    public void setPosition(Position p)
    {
        config.setPosition(p);
    }

    public void setText(String title)
    {
        config.setTitle(title);
    }

    public void setTextRenderingHint(Object hint)
    {
        config.setTextRenderingHint(hint);
    }
}
